﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace DynamicGeometry
{
    public abstract class ShapeBase<TShape> : FigureBase
        where TShape : UIElement
    {
        public ShapeBase()
        {
            Shape = CreateShape();
            ZIndex = DefaultZOrder();
        }

        protected virtual int DefaultZOrder()
        {
            return (int)ZOrder.Figures;
        }

        private TShape shape;
        public TShape Shape
        {
            get
            {
                return shape;
            }
            set
            {
                shape = value;
                if (shape != null)
                {
                    Canvas.SetZIndex(shape, ZIndex);
                }
            }
        }

        public override int ZIndex
        {
            get
            {
                return base.ZIndex;
            }
            set
            {
                base.ZIndex = value;
                if (shape != null)
                {
                    Canvas.SetZIndex(shape, ZIndex);
                }
            }
        }

        protected abstract TShape CreateShape();

        /// <summary>
        /// Implementation of the IMovable.MoveTo method
        /// </summary>
        /// <example>
        /// Usually just MoveToCore (set coordinates) and UpdateVisual
        /// </example>
        /// <param name="newPosition">Coordinates to move this shape to</param>
        public void MoveTo(Point newPosition)
        {
            MoveToCore(newPosition);
            UpdateVisual();
        }

        public virtual void MoveToCore(Point newLocation)
        {
            
        }

        public override void UpdateVisual()
        {
            
        }

        public override bool Exists
        {
            get
            {
                return base.Exists;
            }
            set
            {
                if (base.Exists == value)
                {
                    return;
                }
                base.Exists = value;
                UpdateShapeVisibility();
            }
        }

        public override bool Visible
        {
            get
            {
                return base.Visible;
            }
            set
            {
                base.Visible = value;
                UpdateShapeVisibility();
            }
        }

        public override bool Selected
        {
            get
            {
                return base.Selected;
            }
            set
            {
                base.Selected = value;
                UpdateShapeAppearance();
            }
        }

        protected void UpdateShapeVisibility()
        {
            bool needsToBeVisible = Exists && Visible;
            if (Shape != null && (Shape.Visibility == Visibility.Visible) != needsToBeVisible)
            {
                Shape.Visibility = needsToBeVisible ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        protected virtual void UpdateShapeAppearance()
        {
            System.Windows.Shapes.Shape shape = Shape as System.Windows.Shapes.Shape;
            if (shape == null)
            {
                return;
            }
            if (base.Selected)
            {
                shape.Stroke = new SolidColorBrush(Colors.Red);
            }
            else
            {
                shape.Stroke = new SolidColorBrush(Colors.Black);
            }
        }

        public override void OnAddingToCanvas(Canvas newContainer)
        {
            base.OnAddingToCanvas(newContainer);
            newContainer.Children.Add(Shape);
        }

        public override void OnRemovingFromCanvas(Canvas leavingContainer)
        {
            base.OnRemovingFromCanvas(leavingContainer);
            leavingContainer.Children.Remove(Shape);
        }

        public override void ReadXml(System.Xml.Linq.XElement element)
        {
            base.ReadXml(element);
            var stroke = element.ReadString("Stroke");
            if (!stroke.IsEmpty())
            {
                Shape.SetValue(
                    System.Windows.Shapes.Shape.StrokeProperty,
                    new SolidColorBrush(stroke.ToColor()));
            }
            var strokeThickness = element.ReadDouble("StrokeThickness");
            if (strokeThickness != 0)
            {
                Shape.SetValue(
                    System.Windows.Shapes.Shape.StrokeThicknessProperty,
                    strokeThickness);
            }

            var visible = element.ReadString("Visible");
            if (!visible.IsEmpty()
                && visible.Equals("false", StringComparison.InvariantCultureIgnoreCase))
            {
                Shape.Visibility = Visibility.Collapsed;
            }
        }
    }
}
